import os
import logging
from typing import Optional, Dict, Any

# 导入配置管理工具
from utils.config_utils import get_oss_config

# 尝试导入OSS库
try:
    import oss2
    OSS_AVAILABLE = True
except ImportError:
    OSS_AVAILABLE = False
    logging.error("未安装oss2库，OSS上传功能将不可用")

# 日志配置
logger = logging.getLogger(__name__)

class OSSUploader:
    """阿里云OSS文件上传工具类"""
    
    def __init__(self, config=None, access_key_id=None, access_key_secret=None, endpoint=None, bucket_name=None, cdn_host=None):
        """
        初始化OSS客户端

        Args:
            config: OSS配置字典，如果提供则忽略其他参数
            access_key_id: 阿里云OSS访问密钥ID
            access_key_secret: 阿里云OSS访问密钥Secret
            endpoint: OSS服务端点
            bucket_name: OSS存储桶名称
            cdn_host: CDN主机地址
        """
        # 如果提供了配置字典，则使用它
        if config:
            # 直接使用配置，提取alioss_bucket中的public配置
            if 'alioss_bucket' in config and 'public' in config['alioss_bucket']:
                bucket_config = config['alioss_bucket']['public']
                self.access_key_id = bucket_config.get('alioss_access_id')
                self.access_key_secret = bucket_config.get('alioss_access_key')
                self.endpoint = bucket_config.get('alioss_hostname')
                self.cdn_host = bucket_config.get('cdn_host')
            else:
                # 如果没有找到alioss_bucket配置，使用整个配置
                self.access_key_id = config.get('access_key_id')
                self.access_key_secret = config.get('access_key_secret')
                self.endpoint = config.get('endpoint')
                self.cdn_host = config.get('cdn_host')
        else:
            # 从配置文件获取默认配置
            config_data = None
            try:
                config_data = get_oss_config()
                bucket_config = config_data['alioss_bucket']['public']
                self.access_key_id = bucket_config.get('alioss_access_id')
                self.access_key_secret = bucket_config.get('alioss_access_key')
                self.endpoint = bucket_config.get('alioss_hostname')
                self.bucket_name = bucket_config.get('name')
                self.cdn_host = bucket_config.get('cdn_host')
            except Exception as e:
                logger.warning(f"无法从配置文件加载OSS配置: {str(e)}")

            # 如果提供了单独的参数，则覆盖配置文件中的值
        if access_key_id:
            self.access_key_id = access_key_id
        if access_key_secret:
            self.access_key_secret = access_key_secret
        if bucket_name:
            self.bucket_name = bucket_name
        if cdn_host:
            self.cdn_host = cdn_host

        # 参数验证
        if not self.access_key_id:
            self.access_key_id = os.getenv('ALIOSS_ACCESS_ID')
        if not self.access_key_secret:
            self.access_key_secret = os.getenv('ALIOSS_ACCESS_KEY')
        if not self.cdn_host:
            self.cdn_host = os.getenv('ALIOSS_CDN_HOST')

        # 创建OSS客户端
        if not OSS_AVAILABLE:
            raise RuntimeError("未安装oss2库，OSS上传功能不可用")
        
        try:
            # 创建认证对象
            self.auth = oss2.Auth(self.access_key_id, self.access_key_secret)
            # 创建Bucket对象
            self.bucket = oss2.Bucket(self.auth, self.endpoint, self.bucket_name)
            logger.info(f"OSS客户端初始化成功 - 端点: {self.endpoint}, 存储桶: {self.bucket_name}")
        except Exception as e:
            logger.error(f"OSS客户端初始化失败: {str(e)}")
            raise
    
    def upload_file(self, local_file_path, oss_object_key):
        """
        上传本地文件到OSS
        
        Args:
            local_file_path: 本地文件路径
            oss_object_key: OSS对象键
        
        Returns:
            str: 上传后的文件URL
        """
        # 检查OSS客户端是否可用
        if not OSS_AVAILABLE or not self.bucket:
            raise RuntimeError("OSS客户端未初始化，无法上传文件")
        
        try:
            # 检查文件是否存在
            if not os.path.exists(local_file_path):
                raise FileNotFoundError(f"文件不存在: {local_file_path}")
            
            # 上传文件到OSS
            logger.info(f"正在上传文件 {local_file_path} 到 {oss_object_key}")
            self.bucket.put_object_from_file(oss_object_key, local_file_path)
            file_url = f"{self.cdn_host}/{oss_object_key}"
            logger.info(f"文件上传成功 - 本地路径: {local_file_path}, OSS对象键: {oss_object_key}, URL: {file_url}")
            return file_url
        except Exception as e:
            logger.error(f"文件上传失败 - 本地路径: {local_file_path}, OSS对象键: {oss_object_key}, 错误: {str(e)}")
            raise
    
    def upload_bytes(self, byte_data, oss_object_key):
        """
        上传字节数据到OSS
        
        Args:
            byte_data: 字节数据
            oss_object_key: OSS对象键
        
        Returns:
            str: 上传后的文件URL
        """
        # 检查OSS客户端是否可用
        if not OSS_AVAILABLE or not self.bucket:
            raise RuntimeError("OSS客户端未初始化，无法上传字节数据")
        
        try:
            # 上传字节数据到OSS
            logger.info(f"正在上传字节数据到 {oss_object_key}")
            self.bucket.put_object(oss_object_key, byte_data)
            file_url = f"{self.cdn_host}/{oss_object_key}"
            logger.info(f"字节数据上传成功 - OSS对象键: {oss_object_key}, URL: {file_url}")
            return file_url
        except Exception as e:
            logger.error(f"字节数据上传失败 - OSS对象键: {oss_object_key}, 错误: {str(e)}")
            raise

# 创建默认的OSS上传器实例
def get_oss_uploader(config=None):
    """
    获取OSS上传工具实例

    Args:
        config: 自定义OSS配置

    Returns:
        OSSUploader: OSS上传工具实例
    """
    try:
        if config:
            return OSSUploader(config=config)
        else:
            # 获取OSS配置
            config_data = get_oss_config()
            
            # 直接使用配置，提取alioss_bucket中的public配置
            if 'alioss_bucket' in config_data and 'public' in config_data['alioss_bucket']:
                bucket_config = config_data['alioss_bucket']['public']
                return OSSUploader(
                    access_key_id=bucket_config.get('alioss_access_id'),
                    access_key_secret=bucket_config.get('alioss_access_key'),
                    endpoint=bucket_config.get('alioss_hostname'),
                    bucket_name=bucket_config.get('name'),
                    cdn_host=bucket_config.get('cdn_host')
                )
            else:
                # 如果没有找到alioss_bucket配置，使用整个配置
                return OSSUploader(
                    access_key_id=config_data.get('access_key_id'),
                    access_key_secret=config_data.get('access_key_secret'),
                    endpoint=config_data.get('endpoint'),
                    bucket_name=config_data.get('bucket_name'),
                    cdn_host=config_data.get('cdn_host')
                )
    except Exception as e:
        logger.error(f"创建OSS上传工具失败: {str(e)}")
        return None